/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package src;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;

class ConcurrentBuffer implements Buffer<String> {

    final int n;
    String[] messages;
    int insert = -1;
    int delete = 0;
    int filled = 0;
    
    private final Lock lock = new ReentrantLock();
    private final Condition notEmpty = lock.newCondition();
    private final Condition notFull = lock.newCondition();

    public ConcurrentBuffer(int n) {
        this.n = n;
        messages = new String[n];
    }

    @Override
    public void put(String message) {        
        lock.lock();
        try {
            while (filled == n) {
                notFull.await();
            }
            insert = (insert + 1) % n;
            messages[insert] = message;
            filled++;
            notEmpty.signalAll();
        } catch (InterruptedException ex) {
            Logger.getLogger(ConcurrentBuffer.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            lock.unlock();
        }
    }

    @Override
    public String take() {        
        lock.lock();
        try {
            while (filled == 0) {
                notEmpty.await();
            }
            String message = messages[delete];
            messages[delete] = null;
            delete = (delete + 1) % n;
            filled--;
            notFull.signalAll();
            return message;
        } catch (InterruptedException ex) {
            Logger.getLogger(ConcurrentBuffer.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            lock.unlock();
        }
        return null;
    }
}

/**
 *
 * @author Oksana_Moroz
 */
public class Pr3_2 {
    
    public static void main(String[] args) {
        Buffer<String> buffer = new ConcurrentBuffer(4);
        new Thread(new Producer(buffer)).start();
        new Thread(new Consumer(buffer)).start();
    }
}